/**
 * Copyright 2013 Mr.Hai Mobile Developer. All rights reserved.
 * HAI PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.hector.meinewerk.lib.network.http;

import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.UnknownHostException;

import android.os.AsyncTask;
import android.os.Build;

import com.hector.meinewerk.constants.Constants;
import com.hector.meinewerk.lib.network.http.DataSupplier.Data;
import com.hector.meinewerk.utils.MyLog;

/**
 * DataSuplier interface
 * 
 * @author: AnhND
 * @version: 1.0
 * @since: 1.0
 */
interface DataSupplier {
	public class Data {
		byte[] buffer;
		boolean isFinish;
		int length;
	}

	void getNextPart(Data data);

	void releaseData();

	int overallDataSize();

	void reset();
}

/**
 * 
 * request http
 * 
 * @author: AnhND
 * @version: 1.0
 * @since: Jun 10, 2011
 */
public class HttpAsyncTask extends AsyncTask<Void, Void, Void> {
	private static int CONNECT_TIMEOUT = 120000; // miliseconds: 2phut: thoi
													// gian request
	private static int TIME_OUT = 180000;// miliseconds: 3phut: thoi gian
											// response
	public static int TIME_OUT_PAYMENT = 480000;// miliseconds: 8phut
	public static int TIME_OUT_GET_FILE_SQL = 1000000;// miliseconds:
	public static int TIME_OUT_LOGIN = 30000;// 30 s:
	public static int TIME_OUT_GET_DATA = 60000;// 30 s:
	public static int TIME_OUT_REQUEST = 30000;// 30 s:
	private HTTPRequest request;
	private HTTPResponse response;
	private boolean isSuccess;
	private static final String LOG_TAG = "HttpAsyncTask";
	private int readTimeout = TIME_OUT;
	private int connectTimeout = CONNECT_TIMEOUT;

	public HttpAsyncTask(HTTPRequest re) {
		this.request = re;
		this.readTimeout = TIME_OUT;
	}

	public HttpAsyncTask(HTTPRequest re, int timeout) {
		this.request = re;
		this.readTimeout = timeout;
	}

	public HttpAsyncTask(HTTPRequest re, int connnectTimeOut, int readTimeOut) {
		this.request = re;
		this.connectTimeout = connnectTimeOut;
		this.readTimeout = readTimeOut;
	}

	@Override
	protected Void doInBackground(Void... arg0) {
		if (request == null || request.isAlive() == false) {
			if (request == null) {
				MyLog.i(LOG_TAG, "Request null");
			} else {
				MyLog.i(LOG_TAG, "Request NOT alive");
			}
			return null;
		}

		int countRetry = 0;
		final int NUM_RETRY = 1;
		boolean isRetry = false;
		do {
			isRetry = false;
			countRetry++;
			HttpURLConnection connection = null;
			OutputStream outputStream = null;
			InputStream inputStream = null;
			isSuccess = true;
			// bug sometime response code = -1
			disableConnectionReuseIfNecessary();
			try {
				response = new HTTPResponse(request);
				URL _url = new URL(request.getUrl());
				MyLog.i(LOG_TAG, "Url: "+request.getUrl());
				connection = (HttpURLConnection) _url.openConnection();
				connection.setConnectTimeout(TIME_OUT);
				connection.setReadTimeout(TIME_OUT);
				if (request.getContentType() != null) {
					connection.setRequestProperty("Content-type",
							request.contentType);
					connection
							.setRequestProperty("Accept", request.contentType);
					connection.setRequestProperty("Authorization",
							request.getAuthString());
				}
				connection.setRequestMethod(request.getMethod());

				if (HTTPClient.sessionID != null) {
					connection.setRequestProperty("Cookie",
							HTTPClient.sessionID);
				}

				connection.setDoInput(true);
				if (HTTPRequest.POST.equals(request.getMethod())) {
					connection.setDoOutput(true);
					connection.setUseCaches(false);
					connection.connect();
					DataOutputStream dos = new DataOutputStream(
							connection.getOutputStream());
					dos.write(request.getDataText().getBytes());

				} else if (HTTPRequest.GET.equals(request.getMethod())) {
					connection.setDoOutput(false);
					connection.connect();
				}

				response.code = connection.getResponseCode();
				inputStream = connection.getInputStream();
				response.readData(inputStream);

				if (response.getDataText() == null
						&& response.getDataBinary() == null
						&& request.isAlive()) {
					isSuccess = false;
					isRetry = true;
					StringBuffer strBuffer = new StringBuffer();
					strBuffer.append("ResponseCode: "
							+ connection.getResponseCode());
					strBuffer.append("/ResponseMsg: "
							+ connection.getResponseMessage());
					response.setError(HTTPClient.ERR_UNKNOWN,
							strBuffer.toString());
				}

			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				isSuccess = false;
				response.setError(HTTPClient.ERR_INVALID_URL,
						Constants.MESSAGE_ERROR_NO_CONNECT_SERVER,
						e.getMessage() + "/" + e.toString());
				MyLog.i(LOG_TAG, "MalformedURLException - " + e.getMessage()
						+ "/" + e.toString());
			} catch (FileNotFoundException e) {
				// TODO: handle exception
				isSuccess = false;
				response.setError(HTTPClient.ERR_NOT_FOUND,
						Constants.MESSAGE_ERROR_NO_CONNECT_SERVER,
						e.getMessage() + "/" + e.toString());
				MyLog.i(LOG_TAG, "FileNotFoundException - " + e.getMessage()
						+ "/" + e.toString());
				MyLog.logToFile(
						LOG_TAG,
						"FileNotFoundException - " + e.getMessage() + "/"
								+ e.toString());
			} catch (SocketTimeoutException e) {
				// TODO: handle exception
				isSuccess = false;
				response.setError(HTTPClient.ERR_TIME_OUT,
						Constants.MESSAGE_ERROR_NO_CONNECT_SERVER,
						e.getMessage() + "/" + e.toString());
				MyLog.i(LOG_TAG, "FileNotFoundException - " + e.getMessage()
						+ "/" + e.toString());
				MyLog.logToFile(
						LOG_TAG,
						"FileNotFoundException - " + e.getMessage() + "/"
								+ e.toString());
			} catch (UnknownHostException e) {
				// TODO: handle exception
				isSuccess = false;
				isRetry = true;
				response.setError(HTTPClient.ERR_NO_CONNECTION,
						Constants.MESSAGE_ERROR_NO_CONNECTION, e.getMessage()
								+ "/" + e.toString());
				MyLog.i(LOG_TAG, "FileNotFoundException - " + e.getMessage()
						+ "/" + e.toString());
				MyLog.logToFile(
						LOG_TAG,
						"FileNotFoundException - " + e.getMessage() + "/"
								+ e.toString());
			} catch (IOException e) {
				// TODO Auto-generated catch block
				isSuccess = false;
				isRetry = true;
				response.setError(HTTPClient.ERR_UNKNOWN,
						Constants.MESSAGE_ERROR_NO_CONNECTION, e.getMessage()
								+ "/" + e.toString());
				MyLog.i(LOG_TAG,
						"IOException - " + e.getMessage() + "/" + e.toString());
				MyLog.logToFile(LOG_TAG, "IOException - " + e.getMessage()
						+ "/" + e.toString());
			} catch (Throwable e) {
				// TODO Auto-generated catch block
				isSuccess = false;
				isRetry = true;
				response.setError(HTTPClient.ERR_UNKNOWN,
						Constants.MESSAGE_ERROR_NO_CONNECTION, e.getMessage()
								+ "/" + e.toString());
				MyLog.i(LOG_TAG,
						"Throwable - " + e.getMessage() + "/" + e.toString());
				MyLog.logToFile(LOG_TAG, "Throwable - " + e.getMessage() + "/"
						+ e.toString());
			} finally {
				if (outputStream != null) {
					try {
						outputStream.close();
					} catch (IOException e) {
					}
				}
				if (inputStream != null) {
					try {
						inputStream.close();
					} catch (IOException e) {
					}
				}
				if (connection != null) {
					connection.disconnect();
				}

			}
		} while (countRetry <= NUM_RETRY && isRetry);

		HTTPListenner listenner = null;
		if (response != null) {
			listenner = response.getObserver();
		}
		if (listenner != null) {
			if (isSuccess) {
				listenner.onReceiveData(response);
			} else {
				listenner.onReceiveError(response);
			}
		}
		return null;

	}

	/**
	 * check connection reuse
	 * 
	 * @author: HaiTC
	 * @return: void
	 * @throws:
	 */
	private void disableConnectionReuseIfNecessary() {
		// HTTP connection reuse which was buggy pre-froyo
		if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
			System.setProperty("http.keepAlive", "false");
		}
		System.setProperty("networkaddress.cache.ttl", "0");
		System.setProperty("networkaddress.cache.negative.ttl", "0");
	}

	/**
	 * 
	 * write data
	 * 
	 * @param @param outputStream
	 * @param @param dataSupplier
	 * @param @throws IOException
	 * @return: void
	 * @author: HaiTC3
	 * @date: Mar 9, 2013
	 */
	void writeData(OutputStream outputStream, DataSupplier dataSupplier)
			throws IOException {
		Data data = new Data();
		while (true) {
			dataSupplier.getNextPart(data);
			if (data.buffer != null && data.length > 0) {
				outputStream.write(data.buffer, 0, data.length);
				outputStream.flush();
				dataSupplier.releaseData();
			}
			if (data.isFinish) {
				break;
			}
		}

	}

}
